CloudWatch LogsをターゲットとするEventBridgeルールをCloudFormationで作成するには
困っていた内容
Amazon EventBridge(旧 CloudWatch イベント)のログを CloudWatch Logs ロググループに転送する流れを CloudFormation で実現することはできますか?
または、
CloudFormation で作成したのですが、ログが記録されず、FailedInvocations となります。
どう対応すればいいの?
CloudFormation で EventBridge のルールを作成した上で、さらにリソースベースのポリシーが必要となります。
CloudFormation
コンソールを使って作成する方法が下記のブログにありますが、CloudFormation のテンプレートでも同様に AWS::Events::Rule を作成いただくだけでOKです。
以下、EC2 状態変更を検知するルールを作成したサンプルです。ここではターゲットのロググループも一緒に作成しています。
AWSTemplateFormatVersion: '2010-09-09' Resources: RuleEc2StateChange: Type: AWS::Events::Rule Properties: EventPattern: { "source": [ "aws.ec2" ], "detail-type": [ "EC2 Instance State-change Notification" ] } Targets: - Arn: !GetAtt LogGroupEc2StateChange.Arn Id: LogGroup LogGroupEc2StateChange: Type: AWS::Logs::LogGroup Properties: RetentionInDays: 3 LogGroupName: /aws/events/Ec2StateChange
ただし、このルールが動作するには、次の CloudWatch Logs へのアクセスを許可するリソースベースのポリシーが必要です。
これがなくてもCloudFormationのリソース作成には成功しますが、いざ該当するイベントが発生してルールがトリガーされてもログが入らず、 FailedInvocations メトリクスが記録されることとなります。
リソースベースのポリシー
EventBridge ルールから CloudWatch Logs へのアクセスを許可するためには、CloudWatch Logs のリソースに対するポリシー(リソースベースのポリシー)が必要です。
以下のドキュメントの通り、このポリシーはマネジメントコンソールでのルール作成時に自動的に作成されますが、コンソールを使用しない場合はCLI等で自分で作成する必要があります。
IAMポリシーとは異なり、コンソール上で作成や管理をすることは(現時点では)できず、また紐づけるリソースをポリシー内で記述するため、ポリシーを作成するだけで良くて"アタッチ"をする必要はありません。
EventBridge がログストリームの作成とイベントのログへの記録を許可するには、CloudWatch Logs に EventBridge が CloudWatch Logs に書き込めるようにするリソースベースのポリシーを含める必要があります。AWS マネジメントコンソールを使用して CloudWatch Logs をルールのターゲットに追加する場合、このポリシーは自動的に作成されます。AWS CLI を使用してターゲットを追加する場合、このポリシーが存在しないときは作成する必要があります。
(ドキュメント:CloudWatch Logs のアクセス許可)
既存ポリシーの確認
もし、以前にコンソールから CloudWatch Logs をターゲットとした EventBridge ルールを作成している場合には、既にリソースベースのポリシーが存在しているはずです。ポリシーの有無は、DescribeResourcePoliciesを使って確認します。
% aws logs describe-resource-policies { "resourcePolicies": [ { "policyName": "TrustEventsToStoreLogEvents", "policyDocument": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"TrustEventsToStoreLogEvent\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":[\"delivery.logs.amazonaws.com\",\"events.amazonaws.com\"]},\"Action\":[\"logs:CreateLogStream\",\"logs:PutLogEvents\"],\"Resource\":\"arn:aws:logs:eu-central-1:123456789012:log-group:/aws/events/*:*\"}]}", "lastUpdatedTime": 1622824080912 } ] }
policyDocument
の中身を確認すると、デフォルトで作成されるポリシーでは "Resource": "arn:aws:logs:::log-group:/aws/events/*:*\"
のようにロググループ名でプレフィックスまで指定されています。つまり、「/aws/events/~」のロググループ名のみがターゲットとして許可されている状態です。
コンソール上でルール作成・ターゲット指定する際には、以下のようにデフォルトでこのプレフィックスが付与されます。
既存のロググループから選択する場合でも、このプレフィックスを持つロググループしか選択肢に表示されません。(キャプチャはEventBridgeですが、CloudWatchイベントのコンソールでも同様)
ただし、コンソールを使わなければ任意のロググループ名へログ配信するよう設定することも可能です。その場合には、リソースベースポリシーも次のように変更しましょう。
ポリシーの作成・変更
リソースベースのポリシーがまだ存在しない場合や、既存のものを変更する場合には、 PutResourcePolicy を使います。
必要な権限はドキュメントを参考にしています。
以下の例では、アイルランドリージョンのロググループ(プレフィックス指定なし)へログ配信の許可を付与しています。
aws logs put-resource-policy \ --policy-name "TrustEventsToStoreLogEvents" \ --policy-document '{ "Statement": [ { "Action": [ "logs:CreateLogStream", "logs:PutLogEvents" ], "Effect": "Allow", "Principal": { "Service": "events.amazonaws.com" }, "Resource": "arn:aws:logs:eu-central-1:123456789012:log-group:*", "Sid": "TrustEventsToStoreLogEvent" } ], "Version": "2012-10-17" }'
リソースベースのポリシーは CloudFormation では作成できないのか?
現在(2022.06)はこちらのドキュメントにあるように AWS::Logs::ResourcePolicy
リソースを使うことで対応できるようです。(ご指摘感謝です!)
リソースベースのポリシーは、CloudFormation からの作成が現時点(2021.06)でサポートされていないようです。(以下参考)なので、まだ作成されていない場合には、上述のように CloudFormation とは別に手動で作成する必要があります。
なお、こちらのイシュー(#351)でもいろいろな意見が飛び交っておりますが、各種説について次の通り確認しました:
- スタック内で一緒にIAMロールを作成し、それをルールの
RoleArn
で指定すれば動作する?
いいえ、リソースベースのポリシーは必要で、IAMロールで代替することはできません。IAMロールを作成・RoleArn
に指定しても意味はありません。
- ロググループ名は「/aws/events」で始まらなければならない?
いいえ、任意の名前のロググループへログ配信が可能です。ただし、上述の通りデフォルトのリソースベースポリシーではプレフィックス指定がされているので、必要に応じてポリシーを修正または作成してください。
関連記事
[アップデート] CloudWatch EventsのターゲットとしてCloudWatch Logsがサポートされました!
Amazon CloudWatch Events のログを Amazon CloudWatch Logs Insights で検索してみる!